// Package config 包 config 负责读取和管理应用配置
package config

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"sync"

	"gin_http/utils/config/modules"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

// Config 表示应用的顶层配置结构
type Config struct {
	Server   modules.ServerConfig   `mapstructure:"server" json:"server"`
	Database modules.DatabaseConfig `mapstructure:"database" json:"database"`
	Logger   modules.LoggerConfig   `mapstructure:"logger" json:"logger"`
}

var (
	// 使用 sync.Once 保证配置只初始化一次
	once sync.Once
	// 全局配置单例
	conf *Config
)

// GetConfig 返回配置单例
func GetConfig() *Config {
	// 首次访问时读取并解析配置
	once.Do(func() {
		conf = initConfig()
	})
	// 返回全局配置
	return conf
}

// initConfig 读取并解析配置文件并做必要的处理
func initConfig() *Config {
	// 支持通过环境变量 APP_CONFIG 指定配置文件路径
	cfgFile := os.Getenv("APP_CONFIG")
	if cfgFile != "" {
		// 使用外部指定的配置文件
		viper.SetConfigFile(cfgFile)
	} else {
		// 默认查找 config.yaml（优先 ./config 目录，其次当前目录）
		viper.SetConfigName("config")
		viper.SetConfigType("yaml")
		viper.AddConfigPath("./config")
		viper.AddConfigPath(".")
		// 如果你希望放 /etc/appname，可以再加路径
		// viper.AddConfigPath("/etc/myapp/")
	}

	// 读取配置文件，失败则直接退出
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("读取配置文件错误: %v", err)
	}

	// 反序列化到强类型结构体，便于使用与校验
	c := &Config{}
	if err := viper.Unmarshal(c); err != nil {
		log.Fatalf("解析配置文件错误: %v", err)
	}

	// 可选：开启热加载（生产环境谨慎）
	if c.Server.Env != "prod" {
		// 监听配置文件变化并重新加载到内存
		viper.WatchConfig()
		viper.OnConfigChange(func(e fsnotify.Event) {
			fmt.Printf("配置文件发生变化: %s\n", e.Name)
			// 重新反序列化到 c（注意并发安全）
			_ = viper.Unmarshal(c)
		})
	}

	// 将 logger.path 转为绝对路径，避免相对路径歧义
	if defaultPath := c.Logger.Default.Path; defaultPath != "" {
		abs, err := filepath.Abs(defaultPath)
		if err == nil {
			c.Logger.Default.Path = abs
		}

		// 同时处理模块路径，如果模块没配置 Path，则使用默认路径
		for name, modCfg := range c.Logger.Modules {
			if modCfg.Path == "" {
				modCfg.Path = c.Logger.Default.Path
			} else {
				if absMod, err := filepath.Abs(modCfg.Path); err == nil {
					modCfg.Path = absMod
				}
			}
			c.Logger.Modules[name] = modCfg
		}
	}

	// 返回最终配置
	return c
}
